package com.hlm.st_liveness_detector;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

import androidx.annotation.RequiresApi;

import com.hlm.st_liveness_detector.view.AbstractOverlayView;
import com.hlm.st_liveness_detector.view.SenseCamera;
import com.hlm.st_liveness_detector.view.SenseCameraPreview;
import com.hlm.st_liveness_detector.view.ToastUtil;
import com.sensetime.senseid.sdk.liveness.silent.SilentLivenessApi;
import com.sensetime.senseid.sdk.liveness.silent.common.type.ResultCode;
import com.sensetime.senseid.sdk.liveness.silent.common.util.FileUtil;
import com.sensetime.senseid.sdk.liveness.silent.common.util.ImageUtil;

import java.io.File;
import java.util.List;

abstract class AbstractSilentLivenessActivity extends Activity implements Camera.PreviewCallback, SenseCameraPreview.StartListener {
    public static final int CANCEL_INITIATIVE = 0x101;
    public static final String RESULT_DEAL_ERROR_INNER = "result_deal_error_inner";
    public static final String RESULT_SDK_ERROR_CODE = "result_sdk_error_code";
    public static final String RESULT_CLOUD_INTERNAL_ERROR = "result_cloud_internal_error";
    public static final String RESULT_IMAGE_KEY = "result_image_key";
    public static final String RESULT_FACE_RECT = "result_face_rect";
    public static final String RESULT_INFO = "result_info";

    protected static final String LICENSE_FILE_NAME = "Haolinmeng_SenenID_Silent.lic";
    protected static final String DETECTION_MODEL_FILE_NAME = "M_Detect_Hunter_SmallFace.model";
    protected static final String ALIGNMENT_MODEL_FILE_NAME = "M_Align_occlusion.model";
    protected static final String QUALITY_MODEL_FILE_NAME = "M_Face_Quality.model";
    protected static final String FRAME_SELECTOR_MODEL_FILE_NAME = "M_Liveness_Cnn_half.model";
    protected static final String ANTI_SPOOFING_MODEL_FILE_NAME = "M_Liveness_Antispoofing.model";

    protected View mLoadingView = null;
    protected TextView mTipsView = null;
    protected AbstractOverlayView mOverlayView = null;

    protected SenseCameraPreview mCameraPreviewView = null;
    protected SenseCamera mSenseCamera;

    protected boolean mStartInputData = false;
    protected boolean mIsCanceled = true;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
            getWindow().getDecorView().setSystemUiVisibility(uiFlags);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Window window = getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
        }

        if (!checkPermission(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            final Intent data = new Intent();
            data.putExtra(RESULT_DEAL_ERROR_INNER, true);
            requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},0);
            showError(getString(R.string.common_silent_no_permissions));
            setResult(ActivityUtils.RESULT_CODE_NO_PERMISSIONS, data);
            finish();
            return;
        }

        setContentView(R.layout.common_activity_liveness_silent);

        ((TextView) findViewById(R.id.txt_title)).setText(
                getString(R.string.common_silent_liveness));
        findViewById(R.id.img_back).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                /*Start:codes for normal detection*/
                setResult(RESULT_CANCELED);
                finish();
                /*End*/

                /*Start:codes for rebegin.
                AbstractSilentLivenessActivity.this.reBegin(null);
                return;
                End*/
            }
        });

        this.mTipsView = (TextView) findViewById(R.id.tips);
        this.mTipsView.setText(R.string.common_tracking_missed);
        this.mLoadingView = findViewById(R.id.img_loading);
        this.mTipsView.setText(R.string.common_tracking_missed);
        this.mOverlayView = findViewById(R.id.overlay_silent);

        this.mCameraPreviewView = (SenseCameraPreview) findViewById(R.id.camera_preview);
        this.mCameraPreviewView.setStartListener(this);
        this.mSenseCamera = new SenseCamera.Builder(this).setFacing(SenseCamera.CAMERA_FACING_FRONT)
                .setRequestedPreviewSize(640, 480)
                .build();

        final File externalAssets = new File(this.getFilesDir(), "assets");

        FileUtil.copyAssetsToFile(this, LICENSE_FILE_NAME,
                new File(externalAssets, LICENSE_FILE_NAME).getAbsolutePath());
        FileUtil.copyAssetsToFile(this, DETECTION_MODEL_FILE_NAME,
                new File(externalAssets, DETECTION_MODEL_FILE_NAME).getAbsolutePath());
        FileUtil.copyAssetsToFile(this, ALIGNMENT_MODEL_FILE_NAME,
                new File(externalAssets, ALIGNMENT_MODEL_FILE_NAME).getAbsolutePath());
        FileUtil.copyAssetsToFile(this, QUALITY_MODEL_FILE_NAME,
                new File(externalAssets, QUALITY_MODEL_FILE_NAME).getAbsolutePath());
        FileUtil.copyAssetsToFile(this, FRAME_SELECTOR_MODEL_FILE_NAME,
                new File(externalAssets, FRAME_SELECTOR_MODEL_FILE_NAME).getAbsolutePath());
        FileUtil.copyAssetsToFile(this, ANTI_SPOOFING_MODEL_FILE_NAME,
                new File(externalAssets, ANTI_SPOOFING_MODEL_FILE_NAME).getAbsolutePath());
    }

    @Override
    protected void onResume() {
        super.onResume();

        try {
            this.mCameraPreviewView.start(this.mSenseCamera);
            this.mSenseCamera.setOnPreviewFrameCallback(this);
        } catch (Exception e) {
            setResult(ActivityUtils.RESULT_CODE_CAMERA_ERROR);
            this.finish();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        this.mStartInputData = false;

        if (mLoadingView != null) {
            mLoadingView.clearAnimation();
            mLoadingView.setVisibility(View.GONE);
        }
        SilentLivenessApi.release();

        this.mCameraPreviewView.stop();
        this.mCameraPreviewView.release();

        if (this.mIsCanceled) {
            this.mIsCanceled = false;
            setResult(CANCEL_INITIATIVE);
        }

        if (!isFinishing()) {
            finish();
        }
    }

    @Override
    public void onFail() {
        final Intent data = new Intent();
        data.putExtra(RESULT_DEAL_ERROR_INNER, true);
        setResult(ActivityUtils.RESULT_CODE_CAMERA_ERROR, data);
        if (!isFinishing()) {
            this.finish();
        }
    }

    protected boolean checkPermission(String... permissions) {
        if (permissions == null || permissions.length < 1) {
            return true;
        }
        if (Build.VERSION.SDK_INT < 23) {
            return true;
        }
        for (String permission : permissions) {
            if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * Show error message.
     *
     * @param errorMessage 信息内容
     */
    protected void showError(final String errorMessage) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (!TextUtils.isEmpty(errorMessage)) {
                    ToastUtil.show(AbstractSilentLivenessActivity.this, errorMessage);
                }
            }
        });
    }

    abstract void reBegin(final ResultCode resultCode);

    protected String getErrorNotice(ResultCode resultCode) {
        switch (resultCode) {
            case STID_E_CALL_API_IN_WRONG_STATE:
                return getResources().getString(R.string.common_silent_error_wrong_state);
            case STID_E_CAPABILITY_NOT_SUPPORTED:
                return getResources().getString(
                        R.string.common_silent_error_capability_not_support);
            case STID_E_LICENSE_PLATFORM_NOT_SUPPORTED:
                return getResources().getString(R.string.common_silent_error_platform_not_support);
            case STID_E_LICENSE_INVALID:
                return getResources().getString(R.string.common_silent_error_check_license_fail);
            case STID_E_MODEL_INVALID:
                return getResources().getString(R.string.common_silent_error_check_model_fail);
            case STID_E_MODEL_EXPIRE:
                return getResources().getString(R.string.common_silent_error_model_expire);
            case STID_E_LICENSE_FILE_NOT_FOUND:
                return getResources().getString(
                        R.string.common_silent_error_license_file_not_found);
            case STID_E_LICENSE_BUNDLE_ID_INVALID:
                return getResources().getString(
                        R.string.common_silent_error_license_package_name_mismatch);
            case STID_E_LICENSE_EXPIRE:
                return getResources().getString(R.string.common_silent_error_license_expire);
            case STID_E_MODEL_FILE_NOT_FOUND:
                return getResources().getString(R.string.common_silent_error_model_file_not_found);
            case STID_E_API_KEY_SECRET_NULL:
            case STID_E_API_KEY_INVALID:
                return getResources().getString(R.string.common_silent_error_api_key_secret);
            case STID_E_TIMEOUT:
                return getResources().getString(R.string.common_silent_error_error_time_out);
            case STID_E_SERVER_ACCESS:
                return getResources().getString(R.string.common_silent_error_error_server);
            case STID_E_CHECK_CONFIG_FAIL:
                return getResources().getString(R.string.common_silent_error_check_config_fail);
            case STID_E_NOFACE_DETECTED:
                return getResources().getString(R.string.common_silent_error_action_over);
            case STID_E_DETECT_FAIL:
            case STID_E_HACK:
                return getResources().getString(
                        R.string.common_silent_error_interactive_detection_fail);
            case STID_E_SERVER_TIMEOUT:
                return getResources().getString(R.string.common_silent_error_server_timeout);
            case STID_E_FACE_COVERED:
                return getResources().getString(R.string.common_silent_error_face_covered);
            case STID_E_INVALID_ARGUMENTS:
                return getResources().getString(R.string.common_silent_error_invalid_arguments);
            case STID_E_DETECTION_MODEL_FILE_NOT_FOUND:
                return getResources().getString(
                        R.string.common_silent_error_detection_model_not_found);
            case STID_E_ALIGNMENT_MODEL_FILE_NOT_FOUND:
                return getResources().getString(
                        R.string.common_silent_error_alignment_model_not_found);
            case STID_E_FRAME_SELECTOR_MODEL_FILE_NOT_FOUND:
                return getResources().getString(
                        R.string.common_silent_error_frame_select_model_not_found);
            case STID_E_ANTI_SPOOFING_MODEL_FILE_NOT_FOUND:
                return getResources().getString(
                        R.string.common_silent_error_anti_spoofing_model_not_found);

            default:
                return null;
        }
    }

    protected void saveDataToFile(final byte[] protobuf, final List<byte[]> images) {
        // Codes to save protobuf data.
        if (protobuf != null && protobuf.length > 0) {
            FileUtil.saveDataToFile(protobuf, new File(this.getFilesDir(), "protobuf"
                    + File.separator
                    + "silent_liveness_result_protobuf").getAbsolutePath());
        }

        //Codes to save image results.
        if (images != null && !images.isEmpty()) {
            final File imagesFolder = new File(this.getFilesDir(), "images");
            ImageUtil.saveBitmapToFile(
                    BitmapFactory.decodeByteArray(images.get(0), 0, images.get(0).length),
                    imagesFolder.getAbsolutePath() + File.separator + "silent_liveness_image");
        }
    }
}
